package study.translation.grammar;

import study.translation.utils.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Grammar implements Serializable
{
    private List<Rule> rules = new ArrayList<Rule>();

    private Map<String, Nonterminal> nonterminals = new HashMap<String, Nonterminal>();

    public void addRule( Rule r )
    {
        rules.add( r );
        Nonterminal n = r.getLeftPart();
        nonterminals.put( n.getName(), n );
    }

    public List<Rule> getRules()
    {
        return rules;
    }

    public Collection<Nonterminal> getNonterminals()
    {
        return nonterminals.values();
    }

    public Nonterminal getNonterminal( String name )
    {
        return nonterminals.get( name );
    }

    public Nonterminal createNonterminal( String name )
    {
        if( !nonterminals.containsKey( name ) )
        {
            nonterminals.put( name, new Nonterminal( name ) );
        }
        return nonterminals.get( name );
    }

    public String toBNF()
    {
        return toBNF( false );
    }

    public String toBNF( boolean combine )
    {
        List<String> lines;
        if( combine )
        {
            lines = new ArrayList<String>( nonterminals.size() );
            for( Nonterminal n : getNonterminals() )
            {
                Set<Rule> alternatives = n.getRules();
                List<String> parts = new ArrayList<String>( alternatives.size() );
                for( Rule r : alternatives )
                {
                    parts.add( StringUtils.join( r.getRightPart(), " " ) );
                }
                lines.add( n + " ::= " + StringUtils.join( parts, " | " ) );
            }
        }
        else
        {
            lines = new ArrayList<String>( rules.size() );
            for( Rule r : rules )
            {
                lines.add( r.getLeftPart() + " ::= " + StringUtils.join( r.getRightPart(), " " ) );
            }
        }
        return StringUtils.join( lines, System.getProperty( "line.separator" ) );
    }
}
